
#if UNITY_EDITOR
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
// 定义一个用于UI编辑器的辅助类
namespace MeEditor
{
    /// <summary>
    /// UI编辑器辅助类，提供了一些静态方法来帮助编辑UI元素
    /// </summary>
    public static class UIEditorHelper
    {
        // 定义一个常量向量，用于表示中心点
        private static Vector2 HalfVec = new Vector2(0.5f, 0.5f);

        /// <summary>
        /// 从本地路径加载精灵图
        /// </summary>
        /// <param name="file_path">精灵图文件的路径</param>
        /// <returns>加载的精灵图，如果加载失败则返回null</returns>
        public static Sprite LoadSpriteInLocal(string file_path)
        {
            if (!File.Exists(file_path))
            {
                Debug.Log("LoadSpriteInLocal() cannot find sprite file : " + file_path);
                return null;
            }
            Texture2D texture = LoadTextureInLocal(file_path);
            // 创建Sprite
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), UIEditorHelper.HalfVec);
            return sprite;
        }

        /// <summary>
        /// 从本地路径加载纹理
        /// </summary>
        /// <param name="file_path">纹理文件的路径</param>
        /// <returns>加载的纹理，如果加载失败则返回null</returns>
        public static Texture2D LoadTextureInLocal(string file_path)
        {
            // 创建文件读取流
            FileStream fileStream = new FileStream(file_path, FileMode.Open, FileAccess.Read);
            fileStream.Seek(0, SeekOrigin.Begin);
            // 创建文件长度缓冲区
            byte[] bytes = new byte[fileStream.Length];
            // 读取文件
            fileStream.Read(bytes, 0, (int)fileStream.Length);
            // 释放文件读取流
            fileStream.Close();
            fileStream.Dispose();
            fileStream = null;

            // 创建Texture
            int width = 1080;
            int height = 2340;
            Texture2D texture = new Texture2D(width, height);
            texture.LoadImage(bytes);
            return texture;
        }

        /// <summary>
        /// 创建一个装饰对象-参考图
        /// </summary>
        public static void CreateDecorate()
        {
            if (Selection.activeTransform != null)
            {
                Canvas canvas = Selection.activeTransform.GetComponentInParent<Canvas>();
                if (canvas != null)
                {
                    //UIDecoreate
                    Decoreate decor = CreateEmptyDecorate(canvas.transform);
                    if (decor == null){
                        Debug.Log("CreateDecorate() cannot create decorate");
                        return;
                    }

                    Debug.Log(decor.transform.localPosition);
                    Selection.activeTransform = decor.transform;
                    
                    if (Configure.OpenSelectPicDialogWhenAddDecorate)
                    {
                        bool isSucceed = UIEditorHelper.SelectPicForDecorate(decor);
                        if (!isSucceed)
                            GameObject.DestroyImmediate(decor.gameObject);
                    }
                }
            }
            else
            {
             //弹窗提示没有选中对象
                EditorUtility.DisplayDialog("提示", "请先选中一个对象", "Ok");
            }
        }

        /// <summary>
        /// 创建一个空的装饰对象
        /// </summary>
        /// <param name="parent">装饰对象的父变换</param>
        /// <returns>创建的装饰对象</returns>
        public static Decoreate CreateEmptyDecorate(Transform parent)
        {
            string file_path = Path.Combine(Configure.ResAssetsPath, "Decorate.prefab");
            file_path = FileUtil.GetProjectRelativePath(file_path);
            if (!File.Exists(file_path))
            {
                Debug.LogError("file_path() cannot find decorate prefab");
                return null;
            }
            GameObject decorate_prefab = UnityEditor.AssetDatabase.LoadAssetAtPath(file_path, typeof(UnityEngine.Object)) as GameObject;
            if (decorate_prefab == null)
            {
                Debug.LogError("decorate_prefab() cannot find decorate prefab");
                return null;
            }
            if (decorate_prefab == null)
            {
                Debug.LogError("CreateEmptyDecorate() cannot find decorate prefab");
                return null;
            }
            GameObject decorate = GameObject.Instantiate(decorate_prefab) as GameObject;
            decorate.transform.SetParent(parent);
            RectTransform rectTrans = decorate.transform as RectTransform;
            rectTrans.SetAsFirstSibling();
            //设置anchors中心点 位置位于中心点
            rectTrans.anchorMin = UIEditorHelper.HalfVec;
            rectTrans.anchorMax = UIEditorHelper.HalfVec;
            rectTrans.pivot = UIEditorHelper.HalfVec;
            rectTrans.localPosition = Vector3.zero;
            rectTrans.localScale = Vector3.one;
            Decoreate decor = rectTrans.GetComponent<Decoreate>();
            return decor;
        }

        /// <summary>
        /// 为装饰对象选择图片
        /// </summary>
        /// <param name="decorate">装饰对象</param>
        /// <returns>是否成功选择了图片并应用到装饰对象上</returns>
        public static bool SelectPicForDecorate(Decoreate decorate)
        {
            if (decorate != null)
            {
                string default_path = PathSaver.GetInstance().GetLastPath(PathType.OpenDecorate);
                string spr_path = EditorUtility.OpenFilePanel("加载外部图片", default_path, "");
                if (spr_path.Length > 0)
                {
                    decorate.SprPath = spr_path;
                    PathSaver.GetInstance().SetLastPath(PathType.OpenDecorate, spr_path);
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 生成指定字符串的MD5哈希值
        /// </summary>
        /// <param name="str">要生成哈希值的字符串</param>
        /// <returns>生成的MD5哈希值</returns>
        static public string GenMD5String(string str)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            str = System.BitConverter.ToString(md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(str)), 4, 8);
            return str.Replace("-", "");
        }
        //对prefab查看使用到
        static public void DrawTiledTexture(Rect rect, Texture tex)
        {
            GUI.BeginGroup(rect);
            {
                int width = Mathf.RoundToInt(rect.width);
                int height = Mathf.RoundToInt(rect.height);

                for (int y = 0; y < height; y += tex.height)
                {
                    for (int x = 0; x < width; x += tex.width)
                    {
                        GUI.DrawTexture(new Rect(x, y, tex.width, tex.height), tex);
                    }
                }
            }
            GUI.EndGroup();
        }
        static public string ObjectToGUID(UnityEngine.Object obj)
        {
            string path = AssetDatabase.GetAssetPath(obj);
            return (!string.IsNullOrEmpty(path)) ? AssetDatabase.AssetPathToGUID(path) : null;
        }
        static public T GUIDToObject<T>(string guid) where T : UnityEngine.Object
        {
            if (string.IsNullOrEmpty(guid))
            {
                return null;
            }

            try
            {
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                if (string.IsNullOrEmpty(assetPath))
                {
                    return null;
                }

                UnityEngine.Object obj = AssetDatabase.LoadAssetAtPath(assetPath, typeof(T));
                if (obj == null)
                {
                    return null;
                }

                System.Type objType = obj.GetType();
                if (objType == typeof(T) || objType.IsSubclassOf(typeof(T)))
                {
                    return obj as T;
                }

                if (objType == typeof(GameObject) && typeof(T).IsSubclassOf(typeof(Component)))
                {
                    GameObject go = obj as GameObject;
                    if (go != null)
                    {
                        return go.GetComponent<T>();
                    }
                }

                return null;
            }
            catch (System.Exception)
            {
                return null;
            }
        }
        static Texture2D CreateCheckerTex(Color c0, Color c1)
        {
            Texture2D tex = new Texture2D(16, 16);
            tex.name = "[Generated] Checker Texture";
            tex.hideFlags = HideFlags.DontSave;

            for (int y = 0; y < 8; ++y) for (int x = 0; x < 8; ++x) tex.SetPixel(x, y, c1);
            for (int y = 8; y < 16; ++y) for (int x = 0; x < 8; ++x) tex.SetPixel(x, y, c0);
            for (int y = 0; y < 8; ++y) for (int x = 8; x < 16; ++x) tex.SetPixel(x, y, c0);
            for (int y = 8; y < 16; ++y) for (int x = 8; x < 16; ++x) tex.SetPixel(x, y, c1);

            tex.Apply();
            tex.filterMode = FilterMode.Point;
            return tex;
        }
        static Texture2D mBackdropTex;
        static public Texture2D backdropTexture
        {
            get
            {
                if (mBackdropTex == null) mBackdropTex = CreateCheckerTex(
                    new Color(0.1f, 0.1f, 0.1f, 0.5f),
                    new Color(0.2f, 0.2f, 0.2f, 0.5f));
                return mBackdropTex;
            }
        }
        public static Bounds GetBounds(GameObject obj)
        {
            Vector3 Min = new Vector3(99999, 99999, 99999);
            Vector3 Max = new Vector3(-99999, -99999, -99999);
            MeshRenderer[] renders = obj.GetComponentsInChildren<MeshRenderer>();
            if (renders.Length > 0)
            {
                for (int i = 0; i < renders.Length; i++)
                {
                    if (renders[i].bounds.min.x < Min.x)
                        Min.x = renders[i].bounds.min.x;
                    if (renders[i].bounds.min.y < Min.y)
                        Min.y = renders[i].bounds.min.y;
                    if (renders[i].bounds.min.z < Min.z)
                        Min.z = renders[i].bounds.min.z;

                    if (renders[i].bounds.max.x > Max.x)
                        Max.x = renders[i].bounds.max.x;
                    if (renders[i].bounds.max.y > Max.y)
                        Max.y = renders[i].bounds.max.y;
                    if (renders[i].bounds.max.z > Max.z)
                        Max.z = renders[i].bounds.max.z;
                }
            }
            else
            {
                RectTransform[] rectTrans = obj.GetComponentsInChildren<RectTransform>();
                Vector3[] corner = new Vector3[4];
                for (int i = 0; i < rectTrans.Length; i++)
                {
                    //获取节点的四个角的世界坐标，分别按顺序为左下左上，右上右下
                    rectTrans[i].GetWorldCorners(corner);
                    if (corner[0].x < Min.x)
                        Min.x = corner[0].x;
                    if (corner[0].y < Min.y)
                        Min.y = corner[0].y;
                    if (corner[0].z < Min.z)
                        Min.z = corner[0].z;

                    if (corner[2].x > Max.x)
                        Max.x = corner[2].x;
                    if (corner[2].y > Max.y)
                        Max.y = corner[2].y;
                    if (corner[2].z > Max.z)
                        Max.z = corner[2].z;
                }
            }

            Vector3 center = (Min + Max) / 2;
            Vector3 size = new Vector3(Max.x - Min.x, Max.y - Min.y, Max.z - Min.z);
            return new Bounds(center, size);
        }
        public static Texture GetAssetPreview(GameObject obj)
        {
            GameObject canvas_obj = null;
            GameObject clone = GameObject.Instantiate(obj);
            Transform cloneTransform = clone.transform;
            bool isUINode = false;
            // Debug.Log("GetAssetPreview >>1");
            if (cloneTransform is RectTransform)
            {
                //如果是UGUI节点的话就要把它们放在Canvas下了
                canvas_obj = new GameObject("render canvas", typeof(Canvas));
                Canvas canvas = canvas_obj.GetComponent<Canvas>();
                cloneTransform.SetParent(canvas_obj.transform);
                cloneTransform.localPosition = Vector3.zero;

                canvas_obj.transform.position = new Vector3(-1000, -1000, -1000);
                // 设置宽高
                //根据cloneTransform内容height和width来设置canvas的sizeDelta
                float cloneWidth = cloneTransform.GetComponent<RectTransform>().rect.width;
                float cloneHeight = cloneTransform.GetComponent<RectTransform>().rect.height;
                //如果Anchors 为全屏的话单独设置宽高
                if (cloneTransform.GetComponent<RectTransform>().anchorMin == Vector2.zero && cloneTransform.GetComponent<RectTransform>().anchorMax == Vector2.one)
                {
                    //子节点是否包含名称为safe_area的节点
                    bool containsSafeAreaKeyword = false;
                    //获取子对象名称
                    foreach (RectTransform child in cloneTransform)
                    {
                        if (child.name.Contains("anim") || child.name.Contains("UIRoot") || child.name.Contains("pbui_common"))
                        {
                            containsSafeAreaKeyword = true;
                            break;
                        }
                    }
                    if (containsSafeAreaKeyword)
                    {
                        cloneWidth = 1080.0f;
                        cloneHeight = 2340.0f;
                    }
                    else
                    {
                        cloneWidth = 500.0f;
                        cloneHeight = 500.0f;
                    }
                }
                

                if (cloneWidth == 0)
                {
                    cloneWidth = 1080.0f;
                }
                if (cloneHeight == 0)
                {
                    cloneHeight = 2340.0f;
                }
                canvas_obj.GetComponent<RectTransform>().sizeDelta = new Vector2(cloneWidth, cloneHeight);
                // 缩放
                //canvas_obj.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f);
                canvas_obj.layer = 21;//放在21层，摄像机也只渲染此层的，避免混入了奇怪的东西
                isUINode = true;
            }
            else
                cloneTransform.position = new Vector3(-1000, -1000, -1000);

            Transform[] all = clone.GetComponentsInChildren<Transform>();
            foreach (Transform trans in all)
            {
                trans.gameObject.layer = 21;
            }

            Bounds bounds = GetBounds(clone);
            Vector3 Min = bounds.min;
            Vector3 Max = bounds.max;
            //添加相机
            GameObject cameraObj = new GameObject("render camera");
            Camera renderCamera = cameraObj.AddComponent<Camera>();
            renderCamera.backgroundColor = new Color(0, 0, 0, 1f);
            renderCamera.clearFlags = CameraClearFlags.Color;
            renderCamera.cameraType = CameraType.Preview;
            renderCamera.cullingMask = 1 << 21;
            if (isUINode)
            {
                cameraObj.transform.position = new Vector3((Max.x + Min.x) / 2f, (Max.y + Min.y) / 2f, cloneTransform.position.z-100);
                Vector3 center = new Vector3((Max.x + Min.x) / 2f, (Max.y + Min.y) / 2f, cloneTransform.position.z);
                //+0.01f是为了去掉Unity自带的摄像机旋转角度为0的打印，太烦人了
                cameraObj.transform.LookAt(center);

                renderCamera.orthographic = true;
                float width = Max.x - Min.x;
                float height = Max.y - Min.y;
                float max_camera_size = width > height ? width : height;
                renderCamera.orthographicSize = max_camera_size / 2;//预览图要尽量少点空白
            }
            else
            {
                cameraObj.transform.position = new Vector3((Max.x + Min.x) / 2f, (Max.y + Min.y) / 2f, Max.z + (Max.z - Min.z));
                Vector3 center = new Vector3(cloneTransform.position.x+0.01f, (Max.y + Min.y) / 2f, cloneTransform.position.z);
                cameraObj.transform.LookAt(center);

                int angle = (int)(Mathf.Atan2((Max.y - Min.y) / 2, (Max.z - Min.z)) * 180 / 3.1415f * 2);
                renderCamera.fieldOfView = angle;
            }
            RenderTexture texture = new RenderTexture(400, 400, 0, RenderTextureFormat.Default);
            renderCamera.targetTexture = texture;

            Undo.DestroyObjectImmediate(cameraObj);
            Undo.PerformUndo();
            //不知道为什么要删掉再Undo回来后才Render得出来UI的节点，3D节点是没这个问题的，估计是Canvas创建后没那么快有效？
            renderCamera.RenderDontRestore();
            RenderTexture tex = new RenderTexture(400, 400, 0, RenderTextureFormat.Default);
            Graphics.Blit(texture, tex);
            if(canvas_obj!=null){
                
                Object.DestroyImmediate(canvas_obj);
            }
            if(cameraObj!=null)
            {
                Object.DestroyImmediate(cameraObj);
            }
            return tex;
        }
        public static bool SaveTextureToPNG(Texture inputTex, string save_file_name)
        {
            RenderTexture temp = RenderTexture.GetTemporary(inputTex.width, inputTex.height, 0, RenderTextureFormat.ARGB32);
            Graphics.Blit(inputTex, temp);
            bool ret = SaveRenderTextureToPNG(temp, save_file_name);
            RenderTexture.ReleaseTemporary(temp);
            return ret;

        }
        //将RenderTexture保存成一张png图片  
        public static bool SaveRenderTextureToPNG(RenderTexture rt, string save_file_name)
        {
            RenderTexture prev = RenderTexture.active;
            RenderTexture.active = rt;
            Texture2D png = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
            png.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
            byte[] bytes = png.EncodeToPNG();
            string directory = Path.GetDirectoryName(save_file_name);
            if (!Directory.Exists(directory))
                Directory.CreateDirectory(directory);
            FileStream file = File.Open(save_file_name, FileMode.Create);
            BinaryWriter writer = new BinaryWriter(file);
            writer.Write(bytes);
            file.Close();
            Texture2D.DestroyImmediate(png);
            png = null;
            RenderTexture.active = prev;
            return true;

        }
                

    }
}
#endif